package com.andryu.opengl.java

import android.content.Context
import android.opengl.GLES30
import com.andryu.base.LogUtils
import com.andryu.base.observer.OpenglJavaObserver
import com.andryu.opengl.utils.ShaderUtils
import dagger.hilt.android.qualifiers.ApplicationContext
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.FloatBuffer
import java.nio.ShortBuffer
import javax.inject.Inject

/**
 * java实现绘制四边形
 */
class GraphicRectangleImpl@Inject constructor(@ApplicationContext private val context: Context) : OpenglJavaObserver {

    private val rectangleCoords = floatArrayOf(
        -0.5f, 0.5f, 0.0f,
        -0.5f, -0.5f, 0.0f,
        0.5f, -0.5f, 0.0f,
        0.5f, 0.5f, 0.0f
    )
    private val drawOrder = shortArrayOf(0, 1, 2, 0, 2, 3) // order to draw vertices
    private var vertexBuffer: FloatBuffer
    private var shaderProgram: Int = 0
    private var drawListBuffer: ShortBuffer
    private var positionHandle = 0
    private var colorHandle = 0
    private val color = floatArrayOf(0.63f,0.76f, 0.22f,1.0f)

    init {
        val byteBuffer = ByteBuffer.allocateDirect(rectangleCoords.size * 4)
        byteBuffer.order(ByteOrder.nativeOrder())
        vertexBuffer = byteBuffer.asFloatBuffer()
        vertexBuffer.put(rectangleCoords)
        vertexBuffer.position(0)

        val dlb = ByteBuffer.allocateDirect( // (# of coordinate values * 2 bytes per short)
            drawOrder.size * 2
        )
        dlb.order(ByteOrder.nativeOrder())
        drawListBuffer = dlb.asShortBuffer()
        drawListBuffer.put(drawOrder)
        drawListBuffer.position(0)
    }

    override fun onSurfaceCreated() {
        GLES30.glClearColor(1.0f, 1.0f, 1.0f, 1.0f)
        GLES30.glClearDepthf(1.0f)

        GLES30.glEnable(GLES30.GL_DEPTH_TEST)
        GLES30.glDepthFunc(GLES30.GL_LEQUAL)

        shaderProgram = ShaderUtils.createProgram(context.assets, "shader/vertex/rectangle.vert","shader/fragment/rectangle.frag")
        LogUtils.d("createProgram shaderProgram = {?}", shaderProgram.toString())
        // 检查并记录最大顶点属性数量
        val maxVertexAttribs = IntArray(1)
        GLES30.glGetIntegerv(GLES30.GL_MAX_VERTEX_ATTRIBS, maxVertexAttribs, 0)
        LogUtils.d("MAX_VERTEX_ATTRIBS", "Max Vertex Attributes: ${maxVertexAttribs[0]}")
    }

    override fun onSurfaceChanged(width: Int, height: Int) {
        GLES30.glViewport(0, 0, width, height)
    }

    override fun onDrawFrame() {
        GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT or GLES30.GL_DEPTH_BUFFER_BIT)
        GLES30.glUseProgram(shaderProgram)

        positionHandle = GLES30.glGetAttribLocation(shaderProgram,"vPosition")
        if (positionHandle == -1) {
            LogUtils.d("Could not get attrib location for vPosition")
        }
        GLES30.glEnableVertexAttribArray(positionHandle)
        GLES30.glVertexAttribPointer(
            positionHandle,   //属性位置
            3,          //每个顶点的坐标数量(x,y,z)
            GLES30.GL_FLOAT,  //数据类型
            false,   //是否归一化
            0,    //stride（如果顶点数据中包含其他属性，应设置为每个顶点占用的字节数）
            vertexBuffer  //数据缓冲区
        )

        colorHandle = GLES30.glGetUniformLocation(shaderProgram, "vColor")
        if (colorHandle == -1) {
            LogUtils.d("Could not get uniform location for vColor")
        }
        GLES30.glUniform4fv(
            colorHandle, //由 glGetUniformLocation 获取的统一变量位置
            1,  //指定要传递的 vec4 向量的数量
            color, //包含 vec4 数据的浮点数组
            0 //在 value 数组中开始读取数据的位置
        )

        GLES30.glDrawElements(
            GLES30.GL_TRIANGLES, //图元类型
            6, //索引数量
            GLES30.GL_UNSIGNED_SHORT, //索引数据类型
            drawListBuffer
        )
        GLES30.glDisableVertexAttribArray(positionHandle)

        // 检查并报告任何OpenGL错误
        val error = GLES30.glGetError()
        if (error != GLES30.GL_NO_ERROR) {
            LogUtils.d("OpenGLError", "GL Error: $error")
        }
    }

}